package com.ssy.utils.http;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.net.ssl.SSLHandshakeException;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.RequestLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookieSpec;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.impl.cookie.BestMatchSpecFactory;
import org.apache.http.impl.cookie.BrowserCompatSpec;
import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;


/**
 * 封装的httpclient
 * 
 * @author xym
 * @date 2015年5月21日
 */
@SuppressWarnings("deprecation")
public class EasyHttpClient {

	private static Logger log = LoggerFactory.getLogger(EasyHttpClient.class);

	private CloseableHttpClient httpclient;

	public final static String Samsung_S4_User_Agent = "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36";
	/**
	 * 谷歌浏览器请求头
	 */
	public final static String Chorme_User_Agent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36";

	/**
	 * ie11
	 */
	public final static String Ie11_User_Agent = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";

	/**
	 * 判断charset是否合理
	 */
	private static final Pattern patternForCharset = Pattern.compile("charset\\s*=\\s*['\"]*([^\\s;'\"]*)", Pattern.CASE_INSENSITIVE);

	/**
	 * ture httpclient 自动处理302<br>
	 * false 自己的程序处理302,默认
	 */
	private boolean isRedirect = false;

	/**
	 * post数据 使用压缩传输
	 */
	private boolean isChunk = false;
	/**
	 * 这个参数只有在isRedirect=false时生效<br>
	 * false 自己的程序处理302,默认<br>
	 * true 自己处理302，非程序认
	 */
	private boolean isShouDong302 = false;

	/**
	 * 这个参数是为了传值，<br>
	 * 有时候某些需要的字段只能在登陆的时候获得，<br>
	 * 而这个字段在程序中非常有用，这时候需要放到这里<br>
	 */
	private Map<String, Object> extra = new LinkedHashMap<String, Object>();

	/**
	 * 全局header,优先级大于默认，小于最新设置的,不考虑key的大小写
	 */
	private Map<String, String> whole_headers = new LinkedHashMap<String, String>();

	private BasicCookieStore cookieStore = new BasicCookieStore();

	private PoolingHttpClientConnectionManager connectionManager;

	/**
	 * 代理IP
	 */
	private String host;
	/**
	 * 代理端口
	 */
	private int port;

	static int poolSize = 200;
	static int routePoolSize = 200;
	private Map<String, String> errorExceptionMsg = new LinkedHashMap<String, String>();

	public void setProxy(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public EasyHttpClient() {

		CookieSpecProvider easySpecProvider = new CookieSpecProvider() {
			public CookieSpec create(HttpContext context) {

				return new BrowserCompatSpec() {
					public void validate(Cookie cookie, CookieOrigin origin) throws MalformedCookieException {
					}
				};
			}
		};

		// SSLContext sslContext = SSLContexts.createDefault(); // 忽略证书主机名验证
		// SSLConnectionSocketFactory sslsf = new
		// SSLConnectionSocketFactory(sslContext,
		// SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

		// Registry<ConnectionSocketFactory> reg =
		// RegistryBuilder.<ConnectionSocketFactory> create()
		// .register("http",
		// PlainConnectionSocketFactory.INSTANCE).register("https",
		// sslsf).build();
		Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
		// .register("http",
		// PlainConnectionSocketFactory.getSocketFactory())//也可以
				.register("http", PlainConnectionSocketFactory.INSTANCE).register("https", HttpSSLConnectionSocketFactory.sslSocketFactory).build();
		connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
		connectionManager.setDefaultMaxPerRoute(routePoolSize);// 同一个路由允许最大连接数
		connectionManager.setMaxTotal(poolSize);
		// HttpHost localhost = new HttpHost("locahost", 80); //
		// 如果是多网卡，这里选择出口IP？
		// connectionManager.setMaxPerRoute(new HttpRoute(localhost), 50);

		Registry<CookieSpecProvider> r = RegistryBuilder.<CookieSpecProvider> create().register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
				.register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory()).register("easy", easySpecProvider).build();

		int timeout = 10000;// 超时时间
		RequestConfig requestConfig = RequestConfig.custom().setCookieSpec("easy").setSocketTimeout(timeout).setConnectTimeout(timeout)
				.setConnectionRequestTimeout(3000).build();
		ConnectionConfig connectioncfg = ConnectionConfig.custom().setCharset(Charset.forName("UTF-8")).build();
		SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).setTcpNoDelay(true).build();

		HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
			public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
				String msg = exception.getMessage() == null ? "null" : exception.getMessage();
				if (exception instanceof UnknownHostException) {
					msg = "java.net.UnknownHostException: " + msg;
				}
				if (exception instanceof ConnectException) {
					msg = "java.net.ConnectException: " + msg;
				}
				String url = "default";
				if (context != null) {
					HttpRequest o = (HttpRequest) context.getAttribute("http.request");
					if (o != null) {
						RequestLine line = o.getRequestLine();
						if (line != null) {
							String nurl = line.getUri();
							if (nurl != null) {
								url = nurl;
							}
						}
					}
				}
				if (!errorExceptionMsg.containsKey(url)) {
					errorExceptionMsg.put(url, msg);
				}
				if (executionCount >= 3) {
					return false;
				}

				if (exception instanceof SSLHandshakeException) {
					return false;
				} else {
					return true;
				}
			}
		};
		// DefaultProxyRoutePlanner routePlanner = null;
		// if (ProxyInfoUtil.getProxyIp() != null) {
		// HttpHost proxy = new HttpHost(ProxyInfoUtil.getProxyIp(),
		// ProxyInfoUtil.getProxyPort());
		// routePlanner = new DefaultProxyRoutePlanner(proxy);
		// }

		HttpClientBuilder builder = HttpClients.custom()// 默认
				.setConnectionManager(connectionManager)// 链接管理器
				.setDefaultSocketConfig(socketConfig)// socket管理器
				.setRetryHandler(myRetryHandler)// 重试3次
				.setDefaultConnectionConfig(connectioncfg)// 链接配置，如默认字符编码
				.setDefaultCookieSpecRegistry(r)// cookie策略
				.setUserAgent(Ie11_User_Agent)// 浏览器请求头
				.setSSLSocketFactory(HttpSSLConnectionSocketFactory.sslSocketFactory)// 证书
				.setDefaultRequestConfig(requestConfig)// 链接配置，超时等
				.setDefaultCookieStore(cookieStore);// cookie

		// if (routePlanner != null) {
		// builder.setRoutePlanner(routePlanner);
		// }

		builder.addInterceptorFirst(new HttpRequestInterceptor() {

			public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
				if (!request.containsHeader("Accept-Encoding")) {
					request.addHeader("Accept-Encoding", "gzip");
				}
			}
		});

		httpclient = builder.build();

	}

	/**
	 * post提交的方法 如果想提交一段字符串<br>
	 * 那么需要将header中的content-type设置成非application/x-www-form-urlencoded;<br>
	 * 将字符串放到postdata中参数名postdata 以过期，以后使用postFormData
	 * 
	 * @param posturl
	 *            提交的URL
	 * @param header
	 *            请求头
	 * @param postdata
	 *            请求参数
	 * @return
	 * @throws Exception
	 */
	public String Post(String posturl, Map<String, String> header, Map<String, String> postdata) {
		MyHttpEntity entity = postFormData(posturl, header, postdata, "");
		if (entity == null || entity.getHtml() == null) {
			return "";
		}
		return entity.getHtml();
	}

	/**
	 * post提交的方法 如果想提交一段字符串<br>
	 * 那么需要将header中的content-type设置成非application/x-www-form-urlencoded;<br>
	 * 如application/json; charset=UTF-8<br>
	 * 将字符串放到postdata中参数名postdata
	 * 
	 * @param posturl
	 *            提交的URL
	 * @param header
	 *            请求头
	 * @param postdata
	 *            请求参数
	 * @return
	 * @throws Exception
	 */
	public MyHttpEntity postFormData(String posturl, Map<String, String> header, Map<String, String> postdata) {
		return postFormData(posturl, header, postdata, "");
	}

	/**
	 * 将字符串使用post方式提交
	 * 
	 * @param posturl
	 * @param header
	 * @param poststr
	 * @return
	 */
	public String postJsonStr(String posturl, Map<String, String> header, String poststr) {
		
		if (header == null) {
			header = new LinkedHashMap<String, String>();
		}
		header.put("content-type", "application/json; charset=UTF-8");
		Map<String, String> postdata = new LinkedHashMap<String, String>();
		postdata.put("", poststr);
		return postFormData(posturl, header, postdata, "UTF-8").getHtml();
	}
	
	/**
	 * 将字符串使用post方式提交
	 * 
	 * @param posturl
	 * @param header
	 * @param poststr
	 * @return 返回结果字符串
	 */
	public String postJsonUrl(String posturl, Map<String, String> header, Map<String, String>  data) {
		
		String postStr = JSON.toJSONString(data);
		
		if (header == null) {
			header = new LinkedHashMap<String, String>();
		}
		
		header.put("content-type", "application/json; charset=UTF-8");
		Map<String, String> postdata = new LinkedHashMap<String, String>();
		postdata.put("", postStr);
		MyHttpEntity entriry =  postFormData(posturl, header, postdata, "");
		
		return entriry.getHtml();
	}

	/**
	 * post提交的方法 如果想提交一段字符串<br>
	 * 那么需要将header中的content-type设置成非application/x-www-form-urlencoded;<br>
	 * 将字符串放到postdata中参数名postdata
	 * 
	 * @param posturl
	 *            提交的URL
	 * @param header
	 *            请求头
	 * @param postdata
	 *            请求参数
	 * @param charset
	 *            字符集编码
	 * @return
	 * @throws Exception
	 */
	public MyHttpEntity postFormData(String posturl, Map<String, String> header, Map<String, String> postdata, String charset) {
		MyHttpEntity text = null;
		try {
			log.info("begin post url :" + posturl + " .");
			HttpUriRequest request = getHttpUriRequest(posturl, "post", postdata, header);
			text = execute_text(charset, header, request, text);
			log.info("end post url :" + posturl + " .");
		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return text;
	}

	/**
	 * 执行请求，返回文字
	 * 
	 * @param charset
	 * @param httpUriRequest
	 * @return
	 */
	private MyHttpEntity execute_text(String charset, Map<String, String> header, HttpUriRequest httpUriRequest, MyHttpEntity entity) {
		if (entity == null) {
			entity = new MyHttpEntity();
		}
		entity = execute_bytes(charset, header, httpUriRequest, entity, true);
		return entity;
	}

	/**
	 * 执行请求，返回文字
	 * 
	 * @param charset
	 * @param httpUriRequest
	 * @return
	 */
	private MyHttpEntity execute_bytes(String charset, Map<String, String> header, HttpUriRequest httpUriRequest, MyHttpEntity entity, boolean isHtml) {
		if (entity == null) {
			entity = new MyHttpEntity();
		}
		try {
			CloseableHttpResponse httpResponse = httpclient.execute(httpUriRequest);
			int statusCode = httpResponse.getStatusLine().getStatusCode();
			Header heade = httpResponse.getEntity().getContentType();

			if (heade != null) {
				entity.setContent_type(heade.getValue());
				log.info("statusCode : " + statusCode + " ContentType : " + heade.getValue());
			} else {
				log.info("statusCode : " + statusCode + " ContentType : unknown .");
			}
			// 最终URL，针对302，这里判断一下？
			// setFinalUrl(httpUriRequest.getURI().toString());
			entity.setFinalUrl(httpUriRequest.getURI().toString());
			// 访问的URL，如果是第一次访问，那么添加
			if (entity.getUrl() == null) {
				entity.setUrl(httpUriRequest.getURI().toString());
			}

			// 如果httpcode等于302那么本次请求的httpcode是302
			if (!entity.isIssetStatusCode()) {
				entity.setStatusCode(statusCode);
				entity.setIssetStatusCode(true);
			}
			entity.setFinalStatusCode(statusCode);
			if (statusCode == 200) {
				byte[] bytes = getBytes(httpResponse, entity);
				entity.setBytes(bytes);
			} else if (statusCode == 302 || statusCode == 300 || statusCode == 301) {
				URL referer = httpUriRequest.getURI().toURL();
				httpUriRequest.abort();
				Header location = httpResponse.getFirstHeader("Location");
				String locationurl = location.getValue();
				if (!locationurl.startsWith("http")) {
					URL u = new URL(referer, locationurl);
					locationurl = u.toExternalForm();
				}
				if (isShouDong302) {
					entity.setHtml(locationurl);
					return entity;
				}
				return getAndEntity(locationurl, header, charset, entity);
			} else {
				byte[] bytes = getBytes(httpResponse, entity);
				entity.setBytes(bytes);
			}
			if (isHtml) {
				if (entity.getBytes() != null && entity.getBytes().length > 0) {
					getContent(charset, httpResponse, entity);
					try {
						String html = new String(entity.getBytes(), entity.getCharset());
						entity.setHtml(html);
					} catch (UnsupportedEncodingException e) {
						log.error(e.getMessage());
					}
				} else {
					entity.setHtml("");
				}
			}
			entity.setStatus(true);
		} catch (ClientProtocolException e) {
			log.error(e.getMessage());
		} catch (IOException e) {
			log.error(e.getMessage());
			String msg = e.getMessage();
			String url = "default";
			if (httpUriRequest != null) {
				RequestLine line = httpUriRequest.getRequestLine();
				if (line != null) {
					String nurl = line.getUri();
					if (nurl != null) {
						url = nurl;
					}
				}
			}
			if (!errorExceptionMsg.containsKey(url)) {
				errorExceptionMsg.put(url, msg);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		} finally {
			if (httpUriRequest != null) {
				httpUriRequest.abort();
			}
		}
		return entity;
	}

	private MyHttpEntity getAndEntity(String url, Map<String, String> header, String charset, MyHttpEntity entity) {
		try {
			log.info("begin get url :" + url + " .");
			HttpUriRequest request = getHttpUriRequest(url, "get", null, header);
			entity = execute_text(charset, header, request, entity);
			log.info("end get url :" + url + " .");
		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return entity;
	}

	/**
	 * 请求转换成汉字
	 * 
	 * @param charset
	 * @param httpResponse
	 * @return
	 * @throws IOException
	 */
	protected void getContent(String charset, HttpResponse httpResponse, final MyHttpEntity myEntity) throws IOException {
		if ("".equals(charset) || charset == null) {// 没有传递编码
			Header header = httpResponse.getEntity().getContentType();
			// charset
			// 1、encoding in http header Content-Type
			String ContentType = "";
			if (header != null) {
				ContentType = header.getValue();
			}

			String htmlCharset = getHtmlCharset(ContentType, myEntity.getBytes());
			log.debug("charset is " + htmlCharset);
			if (htmlCharset != null) {
				myEntity.setCharset(htmlCharset);
			} else {
				log.debug("Charset autodetect failed, use utf-8 as charset.");
				myEntity.setCharset("utf-8");
			}
		} else {// 如果已经传递编码，那么使用传递的
			myEntity.setCharset(charset);
		}
	}

	private byte[] getBytes(HttpResponse httpResponse, final MyHttpEntity myEntity) throws IOException {
		HttpEntity entity = httpResponse.getEntity();
		byte[] byteContent = null;
		if (entity.isChunked()) {
			BufferedInputStream remoteBIS = new BufferedInputStream(entity.getContent());
			ByteArrayOutputStream baos = new ByteArrayOutputStream(10240);
			int i = remoteBIS.read();
			int j = 0;
			do {
				try {
					baos.write(i);
					i = remoteBIS.read();
				} catch (IOException ex) {
					log.warn("chunked");
					break;
				}
				j++;
				if (j > 1024 * 1024 * 10) {
					break;
				}
			} while (i != -1);
			remoteBIS.close();

			byteContent = baos.toByteArray();
			baos.close();
		} else {
			byteContent = EntityUtils.toByteArray(entity);
		}
		myEntity.setBytes(byteContent);
		return byteContent;
	}

	/**
	 * 通过httpget请求网页内容
	 * 
	 * @param url
	 *            请求的URL
	 * @param header
	 *            请求头
	 * @param charset
	 *            字符集编码
	 * @return
	 * @throws IOException
	 */
	public String Get(String url, Map<String, String> header, String charset) {
		MyHttpEntity text = getAndEntity(url, header, charset, null);
		if (text == null || text.getHtml().length() == 0) {
			return "";
		}
		return text.getHtml();
	}

	/**
	 * 构造请求的方法，如post，get，header等<br>
	 * 设置请求参数，如超时时间
	 * 
	 * @param url
	 *            请求的URL
	 * @param method
	 *            请求的方法
	 * @param postdata
	 *            post的数据
	 * @param headers
	 *            请求头
	 * @return
	 */
	private HttpUriRequest getHttpUriRequest(String url, String method, Map<String, String> postdata, Map<String, String> headers) {
		RequestBuilder requestBuilder = selectRequestMethod(method, postdata, headers).setUri(url);

		requestBuilder.addHeader("Accept", "*/*");
		requestBuilder.addHeader("Connection", "keep-alive");
		Map<String, String> now_header = new LinkedHashMap<String, String>(whole_headers);

		if (headers != null && headers.size() > 0) {
			now_header.putAll(headers);
		}

		for (Map.Entry<String, String> headerEntry : now_header.entrySet()) {
			requestBuilder.addHeader(headerEntry.getKey(), headerEntry.getValue());
		}

		int timeout = 60000;// 超时时间
		RequestConfig.Builder requestConfigBuilder = RequestConfig.custom().setConnectionRequestTimeout(timeout).setSocketTimeout(timeout)
				.setConnectTimeout(timeout)//
				.setRedirectsEnabled(isRedirect)// 设置是否自动跳转
				.setCookieSpec(CookieSpecs.BEST_MATCH);

		// 使用代理
		if (null != host && !"".equals(host) && port > 10) {
			HttpHost proxy = new HttpHost(host, port);
			requestConfigBuilder.setProxy(proxy);
		}

		requestBuilder.setConfig(requestConfigBuilder.build());
		return requestBuilder.build();
	}

	/**
	 * 设置请求参数<br>
	 * 如果想提交一段字符串<br>
	 * 那么需要将header中的content-type设置成非application/x-www-form-urlencoded;<br>
	 * 将字符串放到postdata中参数名postdata
	 * 
	 * @param method
	 * @param postdata
	 * @param headers
	 * @return
	 */
	protected RequestBuilder selectRequestMethod(String method, Map<String, String> postdata, Map<String, String> headers) {
		if (method == null || method.equalsIgnoreCase("get")) {
			return RequestBuilder.get();
		} else if (method.equalsIgnoreCase("post")) {
			RequestBuilder requestBuilder = RequestBuilder.post();
			if (postdata != null) {

				String contenttype = "application/x-www-form-urlencoded; charset=UTF-8";
				/**********************************************************
				 * 先在header中取字符集<br>
				 * 如果字符集不存在，那么在contenttype中取<br>
				 * 如果还不存在使用默认
				 **********************************************************/
				String charset = "";
				if (headers != null && headers.size() > 0) {
					charset = headers.remove("charset");// 提交数据的传输编码
					for (String ksy : headers.keySet()) {
						if ("Content-Type".equalsIgnoreCase(ksy)) {
							contenttype = headers.get(ksy).toLowerCase().trim();
							break;
						}
					}
				}

				// 如果字符集不存在，那么在contenttype中取
				if (null == charset || "".equals(charset) || !checkCharset(charset)) {
					if (contenttype.contains("charset")) {
						// 如果在请求的编码中，存在网页编码，那么提取改编码
						String ncharset = contenttype.substring(contenttype.lastIndexOf("=") + 1, contenttype.length());
						// 如果提取到的编码合法那么使用该编码
						if (checkCharset(ncharset)) {
							charset = ncharset;
						}
					}
				}

				// 如果还不存在使用默认
				if (null == charset || "".equals(charset) || !checkCharset(charset)) {
					charset = "UTF-8";// 提交数据的传输编码
				}

				if ("".equals(contenttype) || contenttype.toLowerCase().contains("x-www-form-urlencoded")) {
					List<NameValuePair> formParams = new ArrayList<NameValuePair>();
					for (String str : postdata.keySet()) {
						NameValuePair n = new BasicNameValuePair(str, postdata.get(str));
						formParams.add(n);
					}

					UrlEncodedFormEntity entity = null;
					try {

						entity = new UrlEncodedFormEntity(formParams, charset);
						if (isChunk) {
							entity.setChunked(true);
						}
					} catch (UnsupportedEncodingException e) {
						log.error(e.getMessage(), e);
					}
					requestBuilder.setEntity(entity);
				} else {

					log.info("post Content-Type : [ " + contenttype + " ] , pay attention to it .");
					String pstdata = postdata.get("postdata");// 提交的数据
					if ("".equals(pstdata) || pstdata == null) {
						pstdata = postdata.get("");// 提交的数据
					}
					if (pstdata == null) {
						pstdata = "";
					}
					StringEntity entity = new StringEntity(pstdata, charset);// 解决中文乱码问题
					entity.setContentType(contenttype);
					if (isChunk) {
						entity.setChunked(true);
					}
					requestBuilder.setEntity(entity);
				}
			} else {
				log.warn("The Method Is Post,But No Post Data .");
			}
			return requestBuilder;
		} else if (method.equalsIgnoreCase("head")) {
			return RequestBuilder.head();
		} else if (method.equalsIgnoreCase("put")) {
			return RequestBuilder.put();
		} else if (method.equalsIgnoreCase("delete")) {
			return RequestBuilder.delete();
		} else if (method.equalsIgnoreCase("trace")) {
			return RequestBuilder.trace();
		}
		throw new IllegalArgumentException("Illegal HTTP Method " + method);
	}

	/**
	 * 根据contenttype,判断网页字符集
	 * 
	 * @param ContentType
	 * @param contentBytes
	 * @return
	 * @throws IOException
	 */
	private static String getHtmlCharset(String ContentType, byte[] contentBytes) throws IOException {

		String charset = getCharset(ContentType);
		if (charset != null && charset.length() > 0) {
			return charset;
		}
		// use default charset to decode first time
		Charset defaultCharset = Charset.defaultCharset();
		String content = new String(contentBytes, defaultCharset.name());
		// 2、charset in meta
		if (content != null && content.length() > 0) {
			Document document = Jsoup.parse(content);
			Elements links = document.select("meta");
			for (Element link : links) {
				// 2.1、html4.01 <meta http-equiv="Content-Type"
				// content="text/html; charset=UTF-8" />
				String metaContent = link.attr("content");
				String metaCharset = link.attr("charset");
				if (metaContent.indexOf("charset") != -1) {
					metaContent = metaContent.substring(metaContent.indexOf("charset"), metaContent.length());
					charset = metaContent.split("=")[1];
					break;
				}
				// 2.2、html5 <meta charset="UTF-8" />
				else if (metaCharset != null && metaCharset.length() > 0) {
					charset = metaCharset;
					break;
				}
			}
		}
		log.debug("Auto get charset: {}" + charset);
		// 3、todo use tools as cpdetector for content decode
		return charset;
	}

	private static String getCharset(String contentType) {
		Matcher matcher = patternForCharset.matcher(contentType);
		if (matcher.find()) {
			String charset = matcher.group(1);
			if (checkCharset(charset)) {
				return charset;
			}
		}
		return null;
	}

	/**
	 * 判断字符集是否合法，jdk提供的竟然报异常。。。
	 * 
	 * @param charset
	 * @return
	 */
	private static boolean checkCharset(String charset) {
		boolean b = false;
		try {
			b = Charset.isSupported(charset);
		} catch (IllegalCharsetNameException e) {
			log.error(e.getMessage());
		}

		return b;
	}

	/**
	 * 通过httpget请求验证码
	 * 
	 * @param url
	 *            请求的URL
	 * @param header
	 *            请求头
	 * @return
	 * @throws IOException
	 */
	public byte[] GetImg(String url, Map<String, String> header) {
		try {
			log.info("begin get url :" + url + " .");
			HttpUriRequest request = getHttpUriRequest(url, "get", null, header);
			MyHttpEntity entity = new MyHttpEntity();
			entity = execute_bytes("", header, request, entity, false);
			byte[] data = entity.getBytes();
			log.info("end get url :" + url + " .");
			return data;
		} catch (Exception e) {
			log.error(e.getMessage());
			return new byte[0];
		}
	}

	public MyHttpEntity getBytes(String url, Map<String, String> header) {
		MyHttpEntity entity = new MyHttpEntity();
		try {
			log.info("begin get url :" + url + " .");
			HttpUriRequest request = getHttpUriRequest(url, "get", null, header);
			entity = execute_bytes("", header, request, entity, false);
			log.info("end get url :" + url + " .");
		} catch (Exception e) {
			log.error(e.getMessage());
			entity.setBytes(new byte[0]);
		}
		return entity;
	}

	public MyHttpEntity getBytes(String url) {
		return getBytes(url, null);
	}

	/**
	 * 通过httpget请求验证码
	 * 
	 * @param url
	 *            请求的URL
	 * @return
	 * @throws IOException
	 */
	public byte[] GetImg(String url) {
		return GetImg(url, null);
	}

	/**
	 * 通过get请求页面内容
	 * 
	 * @param url
	 * @return
	 * @throws IOException
	 */
	public String Get(String url) {
		return Get(url, null, "");
	}

	/**
	 * 通过httpget请求网页内容
	 * 
	 * @param url
	 *            请求的URL
	 * @param header
	 *            请求头
	 * @param charset
	 *            字符集编码
	 * @return
	 * @throws IOException
	 */
	public String get(String url, Map<String, String> header, String charset) {
		MyHttpEntity text = getAndEntity(url, header, charset, null);
		return text.getHtml();
	}

	public void addCookie(Cookie cookie) {
		this.getCookieStore().addCookie(cookie);
	}

	/**
	 * 通过get请求页面内容
	 * 
	 * @param url
	 * @return
	 * @throws IOException
	 */
	public String get(String url) {
		return get(url, null, "");
	}

	/**
	 * 获得cookiestore
	 * 
	 * @return
	 */
	public CookieStore getCookieStore() {
		return cookieStore;
	}

	/**
	 * 使用结束要关闭httpclient
	 */
	public void close() {
		try {
			// connectionManager.shutdown();
			httpclient.close();
		} catch (IOException e) {
			log.error(e.getMessage());
		}
	}

	public static Map<String, String> doHeader(String borrowHeader) {
		Map<String, String> header = new LinkedHashMap<String, String>();
		if (borrowHeader == null || "".equals(borrowHeader) || !borrowHeader.contains(":")) {
			return header;
		}
		String[] h = borrowHeader.split(":", 2);
		header.put(h[0], h[1]);
		return header;
	}

	/**
	 * 将cookiestore转换成string<br>
	 * 如果为空，使用默认对象
	 * 
	 * @param cookieStore
	 * @return
	 */
	public String CookieStore2String(CookieStore cookieStore) {
		if (cookieStore == null) {
			cookieStore = this.getCookieStore();
		}
		StringBuffer sb = new StringBuffer();
		for (Cookie cookie : cookieStore.getCookies()) {
			sb.append(cookie.getName() + "=" + cookie.getValue() + ";");
		}
		String cookie = sb.toString();
		if (cookie.length() > 1) {
			cookie = cookie.substring(0, cookie.length() - 1);
		}
		return cookie;
	}

	public void addCookie(String name, String value, String domain, Date expiry, String path) {
		BasicClientCookie cookie = new BasicClientCookie(name, value);
		if (domain != null && !domain.equals("")) {
			cookie.setDomain(domain);
		}
		if (expiry != null) {
			cookie.setExpiryDate(expiry);
		}
		if (path != null && !path.equals("")) {
			cookie.setPath(path);
		}

		this.getCookieStore().addCookie(cookie);
	}

	/**
	 * 这个参数是为了传值，<br>
	 * 有时候某些需要的字段只能在登陆的时候获得，<br>
	 * 而这个字段在程序中非常有用，这时候需要放到这里<br>
	 * 这个方法永远不会null
	 * 
	 * @return
	 */
	public Map<String, Object> getExtra() {
		if (extra == null) {
			extra = new LinkedHashMap<String, Object>();
		}
		return extra;
	}

	/**
	 * 这个参数是为了传值，<br>
	 * 有时候某些需要的字段只能在登陆的时候获得，<br>
	 * 而这个字段在程序中非常有用，这时候需要放到这里<br>
	 * 
	 * @param name
	 * @param value
	 */
	public void putExtra(String key, Object value) {
		getExtra().put(key, value);
	}

	/**
	 * 自己处理302，非程序
	 * 
	 * @param isShouDong302
	 */
	public void setShouDong302(boolean isShouDong302) {
		this.isShouDong302 = isShouDong302;
	}

	public String getCookieValue(String key) {
		CookieStore cookieStore = this.getCookieStore();
		for (Cookie cookie : cookieStore.getCookies()) {
			if (key.equals(cookie.getName())) {
				return cookie.getValue();
			}
		}
		return "";
	}

	public CloseableHttpClient getHttpclient() {
		return httpclient;
	}

	/**
	 * 全局header,优先级大于默认，小于最新设置的,不考虑key的大小写
	 * 
	 * @param key
	 * @param value
	 */
	public void putWholeHeader(String key, String value) {
		if (whole_headers == null) {
			whole_headers = new LinkedHashMap<String, String>();
		}
		if (StringUtils.isEmpty(key)) {
			key = "";
		}
		if (StringUtils.isEmpty(value)) {
			value = "";
		}
		whole_headers.put(key, value);
	}

	public void setChunk(boolean isChunk) {
		this.isChunk = isChunk;
	}

	public Map<String, String> getErrorExceptionMsg() {
		return errorExceptionMsg;
	}

	public static void main(String[] args) {
		EasyHttpClient e = new EasyHttpClient();
		e.setProxy("192.21.44.55", 808);
		System.out.println(e.Get("http://shbxcx.sn12333.gov.cn/sxlssLogin.do?uname="));
		System.out.println(e.Get("https://nper.cmbc.com.cn/pweb/static/main.html").length());
		System.out.println(e.Get("https://pbsz.ebank.cmbchina.com/CmbBank_GenShell/UI/GenShellPC/Login/Login.aspx").length());
	}

}